#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <sys/signal.h> 
#include <sys/stat.h>
#include <time.h>
#include "clsrv.h"
#include "client.h"
#include "cl.h"

int _srvpid = 0;
int _pid = 0;
int _answer = 0; //answer file ready/not ready

static void siginthandler(int sig);
static void sigusr1handler(int sig);

int
main(int argc, char * argv[])
{
	int fd;
	int end = 0;
	char * inpbuf;
	
	if ((inpbuf= malloc(MAXLINE+1)) == NULL)
	{
		fprintf(stderr, "Memory allocation error\n");
		return 1;
	}

	if((fd=open(_SRVPIDFILE_, O_RDONLY)) == -1)
	{
		perror("Can't get server pid");
		return 1;
	}

	if(read(fd, &_srvpid, sizeof(int)) < sizeof(int))
	{
		perror("Can't get server pid");
		return 1;
	}
	close(fd);

	system("clear");
	printf("Welcome!\n\n");
	
	_pid = getpid();

	signal(SIGINT, siginthandler);
	signal(SIGUSR1, sigusr1handler);

	while (!end && input(PROMPT, inpbuf))
		end = process_line(inpbuf);
	
	free(inpbuf);
	printf("Thanks for using HotelDB!\n\n");
	return 0;
}

int
liberar(char * guest, char * cnumber)
{
	int fd, i;
	char * left;
	time_t rawtime;
	requestT req;
	answerT answer;

	if(guest == NULL || cnumber == NULL)
	{
		fprintf(stderr, "Can't free room, inconsistent parameters.\n");
		return -1;
	}

	for(i=0; cnumber[i]!='\0'; i++)
	{
		if(!isdigit(cnumber[i]))
		{
			fprintf(stderr, "Can't free room, inconsistent parameters.\n");
			return -1;
		}
	}

	req.room = atoi(cnumber);
	req.opcode = FREE; 
	req.pid = _pid;
	strcpy(req.guest, guest);

	while((fd = open(_QFILE_, O_WRONLY | O_CREAT | O_EXCL, 0660)) == -1)
		sleep(1);
	
	if(write(fd, &req, sizeof(requestT)) < sizeof(requestT))
	{
		perror("Error in making request to server");
		return -1;
	}
	close(fd);
	kill(_srvpid, SIGUSR1);

	while(!_answer)
		sleep(1);

	if((fd=open(_AFILE_, O_RDONLY)) == -1)
	{
		perror("Error receiving answer from server");
		return -1;
	}

	if (read(fd, &answer, sizeof(answerT)) < sizeof(answerT))
	{
		perror("Incosistent answer file");
		return -1;
	}
	close(fd);
	remove(_AFILE_);
	remove(_QFILE_);
	_answer = 0;

	if(answer.opcode != FREE)
	{
		fprintf(stderr, "Inconsistent operation code.\n");
		return -1;
	}
	
	if(answer.status != 0)
		printError(answer.status);
	else
	{
		time(&rawtime);
		left = ctime(&rawtime);
		printf("Guest %s has left room %d at %s having arrived at %s", answer.guest, 
								answer.room, left, answer.etime);
	}

	return 1;
}

int
ocupar(char * guest, char * cnumber)
{
	int fd, i;
	time_t rawtime;
	requestT req;
	answerT answer;

	if(guest == NULL || cnumber == NULL)
	{
		fprintf(stderr, "Can't occupy room, inconsistent parameters.\n");
		return -1;
	}

	for(i=0; cnumber[i]!='\0'; i++)
	{
		if(!isdigit(cnumber[i]))
		{
			fprintf(stderr, "Can't occupy room, inconsistent parameters.\n");
			return -1;
		}
	}

	req.opcode = OCCUPY;
	req.pid = _pid;
	req.room = atoi(cnumber);
	strcpy(req.guest, guest);
	
	while((fd=open(_QFILE_, O_WRONLY | O_CREAT | O_EXCL, 0660)) == -1)
		sleep(1);

	if(write(fd, &req, sizeof(requestT)) < sizeof(requestT))
	{
		perror("Incosistent requests file");
		return -1;
	}
	close(fd);
	kill(_srvpid, SIGUSR1);

	while(!_answer)
		sleep(1);

	if((fd=open(_AFILE_, O_RDONLY)) == -1)
	{
		perror("Error receiving answer from server");
		return -1;
	}

	if(read(fd, &answer, sizeof(answerT)) < sizeof(answerT))
	{
		perror("Incosistent answer file");
		return -1;
	}
	close(fd);
	remove(_AFILE_);
	remove(_QFILE_);
	_answer = 0;

	if(answer.opcode != OCCUPY)
	{
		fprintf(stderr, "Inconsistent operation code.\n");
		return -1;
	}
	
	if(answer.status != 0)
		printError(answer.status);
	else
		printf("Room %d was occupied by guest %s at %s", answer.room,
											 answer.guest, answer.etime);
	return 1;
}

int
reservar(char * guest)
{
	int fd, reserved = 0, i;
	requestT req;
	answerT answer;

	if(guest == NULL)
	{
		fprintf(stderr, "Can't reserve room, inconsistent parameters\n");
		return -1;
	}
	
	while((fd=open(_QFILE_, O_WRONLY | O_CREAT | O_EXCL, 0660 )) == -1)
		sleep(1);
	
	req.opcode = RESERVE;
	req.pid = _pid;
	strcpy(req.guest, guest);
	
	if(write(fd, &req, sizeof(requestT)) < sizeof(requestT))
	{
		perror("Incosistent requests file");
		return -1;
	}
	close(fd);
	//printf("cerro qfile\n");
	kill(_srvpid, SIGUSR1);

	while(!_answer)
		sleep(1);

	if((fd=open(_AFILE_, O_RDONLY)) == -1)
	{
		perror("Error receiving answer from server");
		return -1;
	}
	
	if(read(fd, &answer, sizeof(answerT)) < sizeof(answerT))
	{
		perror("Incosistent answer file");
		return -1;
	}
	close(fd);
	remove(_AFILE_);
	remove(_QFILE_);
	_answer = 0;

	if(answer.opcode != RESERVE)
	{
		fprintf(stderr, "Inconsistent operation code.\n");
		return -1;
	}
	
	if(answer.status != 0)
		printError(answer.status);
	else
		printf("Room %d was reserverd for guest %s\n", answer.room, answer.guest);
	
	return 1;
}

int
listar(char * guest)
{
	int fd, i=0;
	char c;
	requestT req;
	answerT answer;

	if(guest == NULL)
	{
		fprintf(stderr, "Can't list rooms, inconsistent parameters\n");
		return -1;
	}
	
	while((fd=open(_QFILE_, O_WRONLY | O_CREAT | O_EXCL, 0660)) == -1)
		sleep(1);

	req.opcode = LIST;
	req.pid = _pid;
	strcpy(req.guest, guest);

	if(write(fd, &req, sizeof(requestT)) < sizeof(requestT))
	{
		perror("Incosistent requests file");
		return -1;
	}
	close(fd);
	kill(_srvpid, SIGUSR1);

//printf("voy a esperar la respuesta\n");
	while(!_answer)
		sleep(1);
//printf("Llego la respuesta\n");

	if((fd=open(_AFILE_, O_RDONLY)) == -1)
	{
		printf("Error receiving answer from server.\n");
		return -1;
	}

	if(read(fd, &answer, sizeof(answerT)) < sizeof(answerT))
	{
		perror("Incosistent answer file");
		return -1;
	}

	if(answer.opcode != LIST)
	{
		fprintf(stderr, "Inconsistent operation code.\n");
		return -1;
	}
	
	if(answer.status != 0)
		printError(answer.status);
	else
	{	
		printf("List of rooms for guest %s:\n", guest);
		while(read(fd, &c, sizeof(char)) == sizeof(char))
			putchar(c);
	}

	close(fd);
	remove(_AFILE_);
	remove(_QFILE_);
	_answer = 0;
	
	return 1;
}

void
printError(int error)
{
	switch(error)
	{
		case EOPEN_DB: fprintf(stderr, "Can't open DB file.\n");
						break;
		
		case EINCON_DB: fprintf(stderr, "Inconsistent DB file.\n");
						break;
		
		case ELOCK_DB: fprintf(stderr, "Error locking DB file.\n");
						break;
		
		case EOCCUP_ROOM: fprintf(stderr, "Error occupying room.\n");
						break;
		
		case EFREE_ROOM: fprintf(stderr, "Error freeing room.\n");
						break;
		
		case ELIST_ROOM: fprintf(stderr, "Error listing rooms.\n");
						break;
		
		case EBOOK_ROOM: fprintf(stderr, "Error booking new room.\n");
						break;
		
		case ENOT_BOOK: fprintf(stderr, "The room is not booked to the required"
											" guest.\n");
						break;
		
		case ENOT_OCCUP: fprintf(stderr, "The room is not occupied by the"
								 " required guest.\n");
						break;
		 
		case ENO_BOOK_OCCUP: fprintf(stderr, "The are no occupied or booked"
								 " rooms at the moment.\n");
						break;
		
		case ENO_FREE: fprintf(stderr, "The are no free rooms"
								 " available at the moment.\n");
						break;
		
		case ENO_BOOK: fprintf(stderr, "The are no reserved rooms"
								 " at the moment.\n");
						break;
		case EOPCODE: fprintf(stderr, "Operation code conflict.\n");
						break;

		default: fprintf(stderr, "General Error.\n");		
	}
}

/* Extra functions */
static void 
siginthandler(int sig)
{
	printf("\nExit!\n");
	exit(1);
}

static void
sigusr1handler(int sig)
{
	_answer = 1;
	return;
}

